from PyQt5.QtWidgets import QOpenGLWidget
from PyQt5.QtCore import QPoint, QTimer, Qt
from PyPhysLeo.display import Camera
from PyPhysLeo.data_core import Vec3F
import numpy as np
from OpenGL.GL import *
from OpenGL.GLU import *
from shader import Shader

vertex_shader_src = '''
#version 450 core
layout(location = 0) in vec4 position;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
    gl_Position = projection * view * model * vec4(position.xyz, 1.0f);
    gl_PointSize = position.w;
}
'''

fragment_shader_src = '''
#version 450 core
out vec4 color;
void main()
{
    color = vec4(1.0f, 1.0f, 0.0f, 1.0f);
}
'''

point_cloud_data = np.array([
    0.0,0.0,0.0,1.0,
    2.0,0.0,0.0,0.5,
    0.0,5.0,0.0,3.0
],dtype=np.float32)

class Window(QOpenGLWidget):

    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.last_pos_ = QPoint()

        # this timer will make your OpenGLWidget flush automatically every 17ms
        self.timer_ = QTimer(self)
        self.timer_.timeout.connect(self.update)
        self.timer_.start(5)

        self.camera_ = Camera()
        self.camera_.setPosition(Vec3F(0, 0, 20))
        self.camera_.setFocusPosition(Vec3F(0, 0, 0))
        self.camera_.setNearClip(0.01)
        self.camera_.setFarClip(1000)

        # shader
        self.shader = Shader()
        self.shader.initShader(vertex_shader_src, fragment_shader_src)

        # vao vbo
        self.vao = glGenVertexArrays(1)
        self.vbo = glGenBuffers(1)
        glBindVertexArray(self.vao[0])
        glBindBuffer(GL_ARRAY_BUFFER, self.vbo[0])
        glBufferData(GL_ARRAY_BUFFER, len(point_cloud_data)*4, point_cloud_data, GL_DYNAMIC_DRAW)
        glVertexAttribPointer(0,4,GL_FLOAT, GL_FALSE, 4*4, None)
        glEnableVertexAttribArray(0)
        glBindVertexArray(0)


    def getCamera(self):
        return self.camera_

    def initializeGL(self):
        glClearColor(0.2,0.3,0.3,1.0)
        glShadeModel(GL_SMOOTH)
        glEnable(GL_DEPTH_TEST)
        print('initialize openGL successfully')

    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        self.shader.begin()
        glBindVertexArray(self.vao)
        glDrawArrays(GL_POINTS, 0, len(point_cloud_data)/4)
        glBindVertexArray(0)
        self.shader.end()
        
    def resizeGL(self, w, h):
        glViewport(0,0,w,h)
        self.camera_.setAspect(w/h)
        
    def mousePressEvent(self, event):
        self.last_pos_ = event.pos()
        
    def mouseMoveEvent(self, event):
        pos = event.pos()
        delta_pos = pos - self.last_pos_
        self.last_pos_ = pos
        scale = 0.02
        focus_pos = np.array(self.camera_.getFocusPosition(),copy = False)
        camera_pos = np.array(self.camera_.getPosition(),copy = False)
        camera_radius = np.linalg.norm(focus_pos-camera_pos)
        
        if event.buttons()&Qt.LeftButton:
            self.camera_.orbitLeft(delta_pos.x()*scale)
            self.camera_.orbitUp(delta_pos.y()*scale)
        elif event.buttons()&Qt.MiddleButton:
            self.camera_.zoomIn(camera_radius*delta_pos.y()*scale)
        elif event.buttons()&Qt.RightButton:
            self.camera_.translateLeft(camera_radius*delta_pos.x()*scale*0.1)
            self.camera_.translateUp(camera_radius*delta_pos.y()*scale*0.1)
            
    def wheelEvent(self, event):
        scale = 0.02
        focus_pos = np.array(self.camera_.getFocusPosition(),copy = False)
        camera_pos = np.array(self.camera_.getPosition(),copy = False)
        camera_radius = np.linalg.norm(focus_pos-camera_pos)
        scroll = event.angleDelta()
        if scroll.y() > 0:
            self.camera_.zoomOut(camera_radius*scale)
        elif scroll.y() < 0:
            self.camera_.zoomIn(camera_radius*scale)
            
        self.last_pos_ = event.pos()
